10x Home

Introduction

Welcome to the SIB Days 2020 - virtual conference Spatial Transcriptomics workshop by 10x genomics!

The purpose of this tutorial will be to walk users through some of the steps necessary to explore data produced by the 10x Genomics Visium Spatial Gene Expression Solution and the Spaceranger pipeline. We will investigate the data sets are all freely available from 10x Genomics.

Seurat Tutorial

Things to know about this workshop

  1. All files that will be used can be found at: /mnt/libs/shared_data/

[Terminal]

  1. Getting started with R and Visium data outside of Seurat at: https://support.10xgenomics.com/spatial-gene-expression/software/pipelines/latest/rkit
  2. Reference genome for all samples is GRCh38/mm10
  3. All 10x software including Spaceranger, and Loupe Browser, can be downloaded from the 10x Support Site
  4. Most Seurat figures can be controlled with patchwork because they are fundamentally ggplot objects. Some really nice examples can be found on the Patchwork GitHub

Exploring Visium Data with Seurat

Load our packages

library(Seurat)
library(ggplot2)
library(patchwork)
library(dplyr)
library(RColorBrewer)

Loading data in a Seurat object

Real Dataset for the tutorial

breast_cancer <- Load10X_Spatial(data.dir = "/mnt/libs/shared_data/human_breast_cancer_1/outs/",
                filename = "V1_Breast_Cancer_Block_A_Section_1_filtered_feature_bc_matrix.h5")

Same data just internal to 10x

breast_cancer <- Load10X_Spatial(data.dir = "/mnt/analysis/marsoc/pipestances/HWHTFDSXX/SPATIAL_RNA_COUNTER_PD/163086/HEAD/outs/", slice = "slice1")

There are a bunch of data sets hosted by the Satija lab in the Seurat Data Package.

Results

QC

Let’s have a look at some basic QC information. Keep in mind that most Seurat plots are ggplot object and can be manipulated as such.

Counts = UMI Features = Genes

plot1 <- VlnPlot(breast_cancer, features = "nCount_Spatial", pt.size = 0.1) + 
  ggtitle("UMI") +
  theme(axis.text.x = element_blank(), 
        axis.title.x = element_blank(), 
        legend.position = "right") +
  NoLegend()

plot2 <- VlnPlot(breast_cancer, features = "nFeature_Spatial", pt.size = 0.1) + 
  ggtitle("Genes") +
  theme(axis.text.x = element_blank(), 
        axis.title.x = element_blank(), 
        legend.position = "right") +
  NoLegend()

plot3 <- SpatialFeaturePlot(breast_cancer, features = "nCount_Spatial") + 
  theme(legend.position = "right")

plot4 <- SpatialFeaturePlot(breast_cancer, features = "nFeature_Spatial") +
  theme(legend.position = "right")

plot1 + plot2 + plot3  + plot4 + plot_layout(nrow = 2, ncol = 2)

Normalization

Spaceranger does normalization for clustering and DE but does not return that normalized matrix

Pre-normalization Raw UMI counts

SpatialFeaturePlot(breast_cancer, features = c("ERBB2", "CD8A"))

SE transform

  • This will take ~3-4 min.

Don’t worry about reachediteration limit warnings. See https://github.com/ChristophH/sctransform/issues/25 for discussion

Default assay will now be set to SCT

breast_cancer <- SCTransform(breast_cancer, assay = "Spatial", verbose = TRUE)
Calculating cell attributes for input UMI matrix
Variance stabilizing transformation of count matrix of size 19751 by 3822
Model formula is y ~ log_umi
Get Negative Binomial regression parameters per gene
Using 2000 genes, 3822 cells

  |                                                                                                                               
  |                                                                                                                         |   0%
  |                                                                                                                               
  |===============                                                                                                          |  12%
  |                                                                                                                               
  |==============================                                                                                           |  25%
  |                                                                                                                               
  |=============================================                                                                            |  38%
  |                                                                                                                               
  |============================================================                                                             |  50%
  |                                                                                                                               
  |============================================================================                                             |  62%
  |                                                                                                                               
  |===========================================================================================                              |  75%
  |                                                                                                                               
  |==========================================================================================================               |  88%
  |                                                                                                                               
  |=========================================================================================================================| 100%
Found 2 outliers - those will be ignored in fitting/regularization step

Second step: Get residuals using fitted parameters for 19751 genes

  |                                                                                                                               
  |                                                                                                                         |   0%
  |                                                                                                                               
  |==                                                                                                                       |   1%
  |                                                                                                                               
  |===                                                                                                                      |   3%
  |                                                                                                                               
  |=====                                                                                                                    |   4%
  |                                                                                                                               
  |======                                                                                                                   |   5%
  |                                                                                                                               
  |========                                                                                                                 |   6%
  |                                                                                                                               
  |=========                                                                                                                |   8%
  |                                                                                                                               
  |===========                                                                                                              |   9%
  |                                                                                                                               
  |============                                                                                                             |  10%
  |                                                                                                                               
  |==============                                                                                                           |  12%
  |                                                                                                                               
  |================                                                                                                         |  13%
  |                                                                                                                               
  |=================                                                                                                        |  14%
  |                                                                                                                               
  |===================                                                                                                      |  15%
  |                                                                                                                               
  |====================                                                                                                     |  17%
  |                                                                                                                               
  |======================                                                                                                   |  18%
  |                                                                                                                               
  |=======================                                                                                                  |  19%
  |                                                                                                                               
  |=========================                                                                                                |  21%
  |                                                                                                                               
  |==========================                                                                                               |  22%
  |                                                                                                                               
  |============================                                                                                             |  23%
  |                                                                                                                               
  |=============================                                                                                            |  24%
  |                                                                                                                               
  |===============================                                                                                          |  26%
  |                                                                                                                               
  |=================================                                                                                        |  27%
  |                                                                                                                               
  |==================================                                                                                       |  28%
  |                                                                                                                               
  |====================================                                                                                     |  29%
  |                                                                                                                               
  |=====================================                                                                                    |  31%
  |                                                                                                                               
  |=======================================                                                                                  |  32%
  |                                                                                                                               
  |========================================                                                                                 |  33%
  |                                                                                                                               
  |==========================================                                                                               |  35%
  |                                                                                                                               
  |===========================================                                                                              |  36%
  |                                                                                                                               
  |=============================================                                                                            |  37%
  |                                                                                                                               
  |===============================================                                                                          |  38%
  |                                                                                                                               
  |================================================                                                                         |  40%
  |                                                                                                                               
  |==================================================                                                                       |  41%
  |                                                                                                                               
  |===================================================                                                                      |  42%
  |                                                                                                                               
  |=====================================================                                                                    |  44%
  |                                                                                                                               
  |======================================================                                                                   |  45%
  |                                                                                                                               
  |========================================================                                                                 |  46%
  |                                                                                                                               
  |=========================================================                                                                |  47%
  |                                                                                                                               
  |===========================================================                                                              |  49%
  |                                                                                                                               
  |============================================================                                                             |  50%
  |                                                                                                                               
  |==============================================================                                                           |  51%
  |                                                                                                                               
  |================================================================                                                         |  53%
  |                                                                                                                               
  |=================================================================                                                        |  54%
  |                                                                                                                               
  |===================================================================                                                      |  55%
  |                                                                                                                               
  |====================================================================                                                     |  56%
  |                                                                                                                               
  |======================================================================                                                   |  58%
  |                                                                                                                               
  |=======================================================================                                                  |  59%
  |                                                                                                                               
  |=========================================================================                                                |  60%
  |                                                                                                                               
  |==========================================================================                                               |  62%
  |                                                                                                                               
  |============================================================================                                             |  63%
  |                                                                                                                               
  |==============================================================================                                           |  64%
  |                                                                                                                               
  |===============================================================================                                          |  65%
  |                                                                                                                               
  |=================================================================================                                        |  67%
  |                                                                                                                               
  |==================================================================================                                       |  68%
  |                                                                                                                               
  |====================================================================================                                     |  69%
  |                                                                                                                               
  |=====================================================================================                                    |  71%
  |                                                                                                                               
  |=======================================================================================                                  |  72%
  |                                                                                                                               
  |========================================================================================                                 |  73%
  |                                                                                                                               
  |==========================================================================================                               |  74%
  |                                                                                                                               
  |============================================================================================                             |  76%
  |                                                                                                                               
  |=============================================================================================                            |  77%
  |                                                                                                                               
  |===============================================================================================                          |  78%
  |                                                                                                                               
  |================================================================================================                         |  79%
  |                                                                                                                               
  |==================================================================================================                       |  81%
  |                                                                                                                               
  |===================================================================================================                      |  82%
  |                                                                                                                               
  |=====================================================================================================                    |  83%
  |                                                                                                                               
  |======================================================================================================                   |  85%
  |                                                                                                                               
  |========================================================================================================                 |  86%
  |                                                                                                                               
  |=========================================================================================================                |  87%
  |                                                                                                                               
  |===========================================================================================================              |  88%
  |                                                                                                                               
  |=============================================================================================================            |  90%
  |                                                                                                                               
  |==============================================================================================================           |  91%
  |                                                                                                                               
  |================================================================================================================         |  92%
  |                                                                                                                               
  |=================================================================================================================        |  94%
  |                                                                                                                               
  |===================================================================================================================      |  95%
  |                                                                                                                               
  |====================================================================================================================     |  96%
  |                                                                                                                               
  |======================================================================================================================   |  97%
  |                                                                                                                               
  |=======================================================================================================================  |  99%
  |                                                                                                                               
  |=========================================================================================================================| 100%
Computing corrected count matrix for 19751 genes

  |                                                                                                                               
  |                                                                                                                         |   0%
  |                                                                                                                               
  |==                                                                                                                       |   1%
  |                                                                                                                               
  |===                                                                                                                      |   3%
  |                                                                                                                               
  |=====                                                                                                                    |   4%
  |                                                                                                                               
  |======                                                                                                                   |   5%
  |                                                                                                                               
  |========                                                                                                                 |   6%
  |                                                                                                                               
  |=========                                                                                                                |   8%
  |                                                                                                                               
  |===========                                                                                                              |   9%
  |                                                                                                                               
  |============                                                                                                             |  10%
  |                                                                                                                               
  |==============                                                                                                           |  12%
  |                                                                                                                               
  |================                                                                                                         |  13%
  |                                                                                                                               
  |=================                                                                                                        |  14%
  |                                                                                                                               
  |===================                                                                                                      |  15%
  |                                                                                                                               
  |====================                                                                                                     |  17%
  |                                                                                                                               
  |======================                                                                                                   |  18%
  |                                                                                                                               
  |=======================                                                                                                  |  19%
  |                                                                                                                               
  |=========================                                                                                                |  21%
  |                                                                                                                               
  |==========================                                                                                               |  22%
  |                                                                                                                               
  |============================                                                                                             |  23%
  |                                                                                                                               
  |=============================                                                                                            |  24%
  |                                                                                                                               
  |===============================                                                                                          |  26%
  |                                                                                                                               
  |=================================                                                                                        |  27%
  |                                                                                                                               
  |==================================                                                                                       |  28%
  |                                                                                                                               
  |====================================                                                                                     |  29%
  |                                                                                                                               
  |=====================================                                                                                    |  31%
  |                                                                                                                               
  |=======================================                                                                                  |  32%
  |                                                                                                                               
  |========================================                                                                                 |  33%
  |                                                                                                                               
  |==========================================                                                                               |  35%
  |                                                                                                                               
  |===========================================                                                                              |  36%
  |                                                                                                                               
  |=============================================                                                                            |  37%
  |                                                                                                                               
  |===============================================                                                                          |  38%
  |                                                                                                                               
  |================================================                                                                         |  40%
  |                                                                                                                               
  |==================================================                                                                       |  41%
  |                                                                                                                               
  |===================================================                                                                      |  42%
  |                                                                                                                               
  |=====================================================                                                                    |  44%
  |                                                                                                                               
  |======================================================                                                                   |  45%
  |                                                                                                                               
  |========================================================                                                                 |  46%
  |                                                                                                                               
  |=========================================================                                                                |  47%
  |                                                                                                                               
  |===========================================================                                                              |  49%
  |                                                                                                                               
  |============================================================                                                             |  50%
  |                                                                                                                               
  |==============================================================                                                           |  51%
  |                                                                                                                               
  |================================================================                                                         |  53%
  |                                                                                                                               
  |=================================================================                                                        |  54%
  |                                                                                                                               
  |===================================================================                                                      |  55%
  |                                                                                                                               
  |====================================================================                                                     |  56%
  |                                                                                                                               
  |======================================================================                                                   |  58%
  |                                                                                                                               
  |=======================================================================                                                  |  59%
  |                                                                                                                               
  |=========================================================================                                                |  60%
  |                                                                                                                               
  |==========================================================================                                               |  62%
  |                                                                                                                               
  |============================================================================                                             |  63%
  |                                                                                                                               
  |==============================================================================                                           |  64%
  |                                                                                                                               
  |===============================================================================                                          |  65%
  |                                                                                                                               
  |=================================================================================                                        |  67%
  |                                                                                                                               
  |==================================================================================                                       |  68%
  |                                                                                                                               
  |====================================================================================                                     |  69%
  |                                                                                                                               
  |=====================================================================================                                    |  71%
  |                                                                                                                               
  |=======================================================================================                                  |  72%
  |                                                                                                                               
  |========================================================================================                                 |  73%
  |                                                                                                                               
  |==========================================================================================                               |  74%
  |                                                                                                                               
  |============================================================================================                             |  76%
  |                                                                                                                               
  |=============================================================================================                            |  77%
  |                                                                                                                               
  |===============================================================================================                          |  78%
  |                                                                                                                               
  |================================================================================================                         |  79%
  |                                                                                                                               
  |==================================================================================================                       |  81%
  |                                                                                                                               
  |===================================================================================================                      |  82%
  |                                                                                                                               
  |=====================================================================================================                    |  83%
  |                                                                                                                               
  |======================================================================================================                   |  85%
  |                                                                                                                               
  |========================================================================================================                 |  86%
  |                                                                                                                               
  |=========================================================================================================                |  87%
  |                                                                                                                               
  |===========================================================================================================              |  88%
  |                                                                                                                               
  |=============================================================================================================            |  90%
  |                                                                                                                               
  |==============================================================================================================           |  91%
  |                                                                                                                               
  |================================================================================================================         |  92%
  |                                                                                                                               
  |=================================================================================================================        |  94%
  |                                                                                                                               
  |===================================================================================================================      |  95%
  |                                                                                                                               
  |====================================================================================================================     |  96%
  |                                                                                                                               
  |======================================================================================================================   |  97%
  |                                                                                                                               
  |=======================================================================================================================  |  99%
  |                                                                                                                               
  |=========================================================================================================================| 100%
Calculating gene attributes
Wall clock passed: Time difference of 2.041615 mins
Determine variable features
Set 3000 variable features
Place corrected count matrix in counts slot
Centering data matrix

  |                                                                                                                               
  |                                                                                                                         |   0%
  |                                                                                                                               
  |==============================                                                                                           |  25%
  |                                                                                                                               
  |============================================================                                                             |  50%
  |                                                                                                                               
  |===========================================================================================                              |  75%
  |                                                                                                                               
  |=========================================================================================================================| 100%
Set default assay to SCT
SpatialFeaturePlot(breast_cancer, features = c("ERBB2", "CD8A"))

From Seurat:

The default parameters in Seurat emphasize the visualization of molecular data. However, you can also adjust the size of the spots (and their transparency) to improve the visualization of the histology image, by changing the following parameters:

pt.size.factor- This will scale the size of the spots. Default is 1.6
alpha - minimum and maximum transparency. Default is c(1, 1).
Try setting to alpha c(0.1, 1), to downweight the transparency of points with lower expression
p1 <- SpatialFeaturePlot(breast_cancer, features = "IGFBP5", pt.size.factor = 1)+ 
  theme(legend.position = "right") +
  ggtitle("Actual Spot Size")
p2 <- SpatialFeaturePlot(breast_cancer, features = "IGFBP5")+ 
  theme(legend.position = "right") +
  ggtitle("Scaled Spot Size")
p1 + p2

Dimensionality reduction, clustering, and visualization

We can then proceed to run dimensionality reduction and clustering on the RNA expression data, using the same workflow as we use for scRNA-seq analysis.

Some of these processes can be parallized

library(future)
# check the current active plan
plan()
# change the current plan to access parallelization
plan("multiprocess", workers = 4)
plan()

The default UMAP calculation is performed with the R-based UWOT library However, you can run UMAP in python via reticulate library and umap-learn. We have found that for smaller data sets (<= 10k cells/spots) UWOT is great. For much larger data sets (100k + cells/spots) umap-learn can be a faster option.

breast_cancer <- RunPCA(breast_cancer, assay = "SCT", verbose = FALSE)
breast_cancer <- FindNeighbors(breast_cancer, reduction = "pca", dims = 1:30)
Computing nearest neighbor graph
Computing SNN
breast_cancer <- FindClusters(breast_cancer, verbose = FALSE)
breast_cancer <- RunUMAP(breast_cancer, reduction = "pca", dims = 1:30)
The default method for RunUMAP has changed from calling Python UMAP via reticulate to the R-native UWOT using the cosine metric
To use Python UMAP via reticulate, set umap.method to 'umap-learn' and metric to 'correlation'
This message will be shown once per session14:26:26 UMAP embedding parameters a = 0.9922 b = 1.112
14:26:26 Read 3822 rows and found 30 numeric columns
14:26:26 Using Annoy for neighbor search, n_neighbors = 30
14:26:26 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:26:27 Writing NN index file to temp file /tmp/RtmpTrBZqF/file780e57b16d8ce
14:26:27 Searching Annoy index using 1 thread, search_k = 3000
14:26:28 Annoy recall = 100%
14:26:28 Commencing smooth kNN distance calibration using 1 thread
14:26:29 Initializing from normalized Laplacian + noise
14:26:32 Commencing optimization for 500 epochs, with 157848 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:26:42 Optimization finished

Now let’s have a look at the clustering

DimPlot(breast_cancer, reduction = "umap", label = FALSE,) +
  labs(color = "Cluster")

p1 <- DimPlot(breast_cancer, reduction = "umap", label = TRUE) +
  labs(color = "Cluster")
p2 <- SpatialDimPlot(breast_cancer, label = TRUE, label.size = 3) +
  labs(fill = "Cluster")

p1 + p2 + plot_annotation(
  title = 'Clustering in UMAP and Tissue Space',
  caption = 'Processed by Spaceranger 1.1\nNormilization and Clustering by Seurat'
) + plot_layout(nrow = 1)

I don’t really like these colors so let’s change them

myPalette <- colorRampPalette(rev(brewer.pal(11, "Spectral")))
p1 <- DimPlot(breast_cancer, reduction = "umap", label = TRUE) +
  labs(color = "Cluster") + 
  scale_color_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green"))

p2 <- SpatialDimPlot(breast_cancer, label = TRUE, label.size = 3) +
  labs(fill = "Cluster")+ 
  scale_fill_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green"))

p1 + p2 + plot_annotation(
  title = 'Clustering in UMAP and Tissue Space',
  caption = 'Processed by Spaceranger 1.1\nNormilization and Clustering by Seurat'
) + plot_layout(nrow = 1)

If interested you can also now look at UMI and Gene counts per cluster as well

plot1 <- VlnPlot(breast_cancer, features = "nCount_Spatial", pt.size = 0.1) + 
  ggtitle("UMI") +
  scale_fill_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green"))+
  theme(axis.text.x = element_blank(), 
        axis.title.x = element_blank(), 
        legend.position = "right") +
  NoLegend()

plot2 <- VlnPlot(breast_cancer, features = "nFeature_Spatial", pt.size = 0.1) + 
  ggtitle("Genes") +
  scale_fill_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green"))+
  theme(axis.title.x = element_blank(), 
        legend.position = "right") +
  NoLegend()

plot1 + plot2

Now let’s take a look at at a gene of interest with violin plots but also in image space.

p1 <- VlnPlot(breast_cancer, features = "IGFBP5", pt.size = 0.1) + 
  ggtitle("IGFBP5") +
  scale_fill_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green"))+
  theme(axis.title.x = element_blank(), 
        legend.position = "right") +
  NoLegend() +
  stat_summary(fun=mean, geom="point", shape=23, size=4, color="red")

p2 <- SpatialFeaturePlot(breast_cancer, features = "IGFBP5")+ 
  theme(legend.position = "right")
CombinePlots is being deprecated. Plots should now be combined using the patchwork system.
p3 <- SpatialDimPlot(breast_cancer, label = TRUE, label.size = 3) +
  labs(fill = "Cluster")+ 
  scale_fill_manual(values = c("#b2df8a","#e41a1c","#377eb8","#4daf4a","#ff7f00","gold", 
                               "#a65628", "#999999", "black", "pink", "purple", "brown",
                               "grey", "yellow", "green")) +
  NoLegend()
CombinePlots is being deprecated. Plots should now be combined using the patchwork system.
row1 <- p2 + p3 + plot_layout(nrow = 1)
row1 + p1+ plot_layout(nrow = 2, widths = c(0.5, 0.5))

We can also look at these data interactively

LinkedDimPlot(breast_cancer)

Spatially variable features

First we’ll identify deferentially expressed genes.

Parallelization helps here too let’s make sure our plan is still intact

plan()

Let’s find all the markers for every cluster

Identify the most up-regulated and down-regulated genes

de_markers_up <- de_markers %>%
  tibble::rownames_to_column(var = "Gene") %>% 
  arrange(-avg_logFC)

de_markers_down <- de_markers %>%
  tibble::rownames_to_column(var = "Gene") %>% 
  arrange(avg_logFC)

Most up-regulated genes

SpatialFeaturePlot(object = breast_cancer, features = de_markers_up$Gene[1:10], alpha = c(0.1, 1), ncol = 3)

Most down-regulated genes

SpatialFeaturePlot(object = breast_cancer, features = de_markers_down$Gene[1:10], alpha = c(0.1, 1), ncol = 3)

what are the top variable features?

VariableFeatures(breast_cancer)[1:10]
 [1] "IGKC"   "IGHG3"  "IGLC2"  "MGP"    "ALB"    "IGHG1"  "CPB1"   "CRISP3" "IGLC3"  "IGHM"  

what are the top DE genes?

rownames(de_markers)[1:10]
 [1] "CRISP3"  "IGFBP5"  "SLITRK6" "H3F3A"   "IGFBP4"  "MALAT1"  "C3"      "KRT18"   "S100A11" "MGP"    

Spatially Variable Genes

So what about spatial enrichment?

Some methods

  1. Trendsceek
  2. Splotch
  3. SPARK
  4. SpatialDE
  • We have found this implementation not to be very effective. It’s also not under active development

Using the top 100 variable genes find spatially enriched ones. Note that in the Seurat Spatial Tutorial they use 1000 genes. You can also use all genes but that will take a long time. Using a calculation of Morans I can sometimes be a faster approach, especially if you are using parallization.

breast_cancer <- FindSpatiallyVariableFeatures(breast_cancer, 
                                               assay = "SCT", 
                                               slot = "scale.data", 
                                               features = VariableFeatures(breast_cancer)[1:100],
                                               selection.method = "markvariogram", verbose = TRUE)

Have a look at the spatially variable genes calculated by markvariogram ordered from most variable to least variable

SpatiallyVariableFeatures(breast_cancer, selection.method = "markvariogram", decreasing = TRUE)
  [1] "CRISP3"     "CXCL14"     "MGP"        "CPB1"       "COX6C"      "SLITRK6"    "TTLL12"     "CCND1"      "MALAT1"    
 [10] "AGR2"       "ALB"        "GFRA1"      "S100G"      "CSTA"       "DEGS1"      "TFF3"       "MT-ND1"     "IGLC2"     
 [19] "MT-CO1"     "IGHG3"      "CD74"       "C6orf141"   "S100A6"     "MT-ND2"     "TFF1"       "IGKC"       "IGHG1"     
 [28] "APOE"       "ZNF350-AS1" "HLA-DRA"    "AC087379.2" "IGHG4"      "C3"         "FCGR3B"     "TIMP1"      "LINC00645" 
 [37] "IGHM"       "SCGB2A2"    "KRT14"      "IGLC3"      "KRT17"      "LYZ"        "APOC1"      "SCGB1D2"    "IGHA1"     
 [46] "C1QA"       "AEBP1"      "APOD"       "KRT5"       "MMP7"       "CCL19"      "COL6A2"     "TAGLN"      "S100A9"    
 [55] "IGHG2"      "COL1A2"     "DCN"        "SPP1"       "COL1A1"     "CGA"        "VIM"        "IGFBP7"     "FN1"       
 [64] "CCDC80"     "CXCL9"      "IGHA2"      "TRBC2"      "SFRP2"      "KRT6B"      "S100A2"     "LUM"        "COL3A1"    
 [73] "IGLC7"      "SAA1"       "CARTPT"     "COMP"       "JCHAIN"     "CST1"       "PTGDS"      "SFRP4"      "CD79A"     
 [82] "CCL21"      "FABP4"      "MUC19"      "ACKR1"      "POSTN"      "MMP9"       "S100A7"     "VWF"        "AQP1"      
 [91] "CLDN5"      "ACTA2"      "MS4A1"      "IGLL5"      "MYH11"      "CXCL10"     "IGHD"       "HBB"        "TPSB2"     
[100] "AC005224.3"
top.features_trendseq <- head(SpatiallyVariableFeatures(breast_cancer, selection.method = "markvariogram"), 8)
SpatialFeaturePlot(breast_cancer, features = top.features_trendseq, ncol = 4, alpha = c(0.1, 1))

Moran’s I implementation. For other spatial data types the x.cuts and y.cuts determines the grid that is laid over the tissue in the capture area. Here we’ll remove those

breast_cancer <- FindSpatiallyVariableFeatures(breast_cancer, 
                                               assay = "SCT", 
                                               slot = "scale.data", 
                                               features = VariableFeatures(breast_cancer)[1:100],
                                               selection.method = "moransi")
Computing Moran's I

Have a look at the spatially variable genes calculated by moransi ordered from most variable to least variable

SpatiallyVariableFeatures(breast_cancer, selection.method = "moransi", decreasing = TRUE)
  [1] "CRISP3"     "CXCL14"     "TTLL12"     "SLITRK6"    "GFRA1"      "CCND1"      "AGR2"       "COX6C"      "MGP"       
 [10] "ALB"        "MALAT1"     "CPB1"       "DEGS1"      "C6orf141"   "CSTA"       "MT-ND1"     "TFF3"       "MT-CO1"    
 [19] "S100A6"     "MT-ND2"     "LINC00645"  "FCGR3B"     "S100G"      "TFF1"       "C3"         "ZNF350-AS1" "HLA-DRA"   
 [28] "CD74"       "SCGB1D2"    "APOD"       "IGLC2"      "TIMP1"      "IGHG3"      "SCGB2A2"    "APOC1"      "KRT14"     
 [37] "LYZ"        "CCDC80"     "APOE"       "TAGLN"      "IGHG1"      "AC087379.2" "CCL19"      "SPP1"       "IGKC"      
 [46] "S100A9"     "KRT17"      "IGHM"       "FN1"        "KRT5"       "IGFBP7"     "C1QA"       "COL6A2"     "AQP1"      
 [55] "CXCL9"      "ACKR1"      "CARTPT"     "DCN"        "AEBP1"      "IGLC3"      "IGHG4"      "VIM"        "S100A2"    
 [64] "IGHG2"      "MMP7"       "IGHA1"      "CCL21"      "KRT6B"      "TRBC2"      "COL1A2"     "CGA"        "SFRP2"     
 [73] "VWF"        "COL1A1"     "SAA1"       "MUC19"      "COL3A1"     "CLDN5"      "SFRP4"      "POSTN"      "PTGDS"     
 [82] "IGHA2"      "JCHAIN"     "CD79A"      "ACTA2"      "LUM"        "CST1"       "S100A7"     "COMP"       "MS4A1"     
 [91] "IGLC7"      "MMP9"       "HBB"        "FABP4"      "MYH11"      "IGLL5"      "CXCL10"     "TPSB2"      "IGHD"      
[100] "AC005224.3"
top.features_moransi <- head(SpatiallyVariableFeatures(breast_cancer, selection.method = "moransi"), 8)
SpatialFeaturePlot(breast_cancer, features = top.features_moransi, ncol = 4, alpha = c(0.1, 1))

We can see that the results are slightly different. So let’s take a look at why.

spatially_variable_genes <- breast_cancer@assays$SCT@meta.features %>%
  tidyr::drop_na()

spatially_variable_genes

You can see the two methods show

mm_cor <- cor.test(spatially_variable_genes$moransi.spatially.variable.rank, spatially_variable_genes$markvariogram.spatially.variable.rank)
ggplot(spatially_variable_genes, aes(x=moransi.spatially.variable.rank,y=markvariogram.spatially.variable.rank))+
  geom_point()+
  geom_smooth()+
  xlab("Morans I Rank")+
  ylab("Markvariogram Rank")+
  annotate("text", x = 25, y = 75, label = paste("Pearson's Correlation\n", round(mm_cor$estimate[1], digits = 2), sep = ""))+
  theme_bw()

Cancer annotations

Where are these genes being expressed relative to pathologist annotation?

ca <- readbitmap::read.bitmap("images/Breast Cancer Path.png")
# in the tutorial
# ca <- readbitmap::read.bitmap('/mnt/libs/shared_data/human_breast_cancer_1/images/Breast_Cancer_Path.png')
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(ca,0,0,1,1)

Looks like the Matrix Gla protein ( MGP ) gene is enriched in Ductal Carcinoma In Situ. Not a lot is known about MGP in the context of cancer but it looks like it could be an interesting novel gene to investigate with regard to Ductal Carcinoma In Situ.

SpatialFeaturePlot(object = breast_cancer, features = "MGP", alpha = c(0.1, 1), ncol = 3)

Multiple Sections

for workshop

breast_cancer_2 <- Load10X_Spatial(data.dir = "/mnt/libs/shared_data/human_breast_cancer_2/outs/",
                filename = "V1_Breast_Cancer_Block_A_Section_2_filtered_feature_bc_matrix.h5")

for 10x

breast_cancer_2 <- Load10X_Spatial(data.dir = "/mnt/analysis/marsoc/pipestances/HWHTFDSXX/SPATIAL_RNA_COUNTER_PD/163087/HEAD/outs/", 
                                   slice = "slice2")
breast_cancer_merged <- merge(breast_cancer, breast_cancer_2)
Some cell names are duplicated across objects provided. Renaming to enforce unique cell names.

Counts = UMI Features = Genes

plot1 <- SpatialFeaturePlot(breast_cancer_merged, features = "nCount_Spatial") + 
  theme(legend.position = "right")

plot2 <- SpatialFeaturePlot(breast_cancer_merged, features = "nFeature_Spatial") +
  theme(legend.position = "right")

plot1 + plot2 + plot_layout(nrow = 2)

Normalize merged data

This will take ~3min

Default assay will now be set to SCT

breast_cancer_merged <- SCTransform(breast_cancer_merged, assay = "Spatial", verbose = TRUE)
SpatialFeaturePlot(breast_cancer_merged, features = c("ERBB2", "CD8A"))

Single cell/nuclei integration

Here we have a preprocessed Seurat object with 10k nuclei annotated from a breast cancer sample. Don’t bother too much with the details of how this data was generated they don’t particularly matter for our purposes.

Load the Seurat object

10x infrastructure

bc_snRNA <- readRDS("/mnt/home/stephen.williams/yard/Odin/SIB_2020_Workshop/bc_snRNA.rds")

For the workshop

bc_snRNA <- readRDS("/mnt/libs/shared_data/bc_snRNA.rds")
bc_snRNA
An object of class Seurat 
56988 features across 10000 samples within 2 assays 
Active assay: SCT (23450 features)
 1 other assay present: RNA
 3 dimensional reductions calculated: pca, harmony, umap

It’s always a good idea to rerun normalization to make sure your data is in the correct format before moving forward with integration.

bc_snRNA <- SCTransform(bc_snRNA, ncells = 3000, verbose = FALSE) %>% 
  RunPCA(verbose = FALSE) %>% 
  RunUMAP(dims = 1:30)

Class

Subclass

snRNA Differentially Expressed Genes

What genes define some cell types?

# Find markers for every cluster compared to all remaining cells, report only the positive ones
# This takes a bit of time so we'll skip it and move on to specific cell types
de_markers_snRNA <- FindAllMarkers(bc_snRNA, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
de_markers_snRNA %>% 
  group_by(cluster) %>% 
  top_n(n = 2, wt = avg_logFC)

Find markers that define tumors

Find markers that define tumors

Find markers that define stem cells

Identify and Transfer Anchors

anchors <- FindTransferAnchors(reference = bc_snRNA, query = breast_cancer,normalization.method = "SCT")

predictions.assay <- TransferData(anchorset = anchors, refdata = bc_snRNA$subclass, prediction.assay = TRUE, 
    weight.reduction = breast_cancer[["pca"]])

breast_cancer[["predictions"]] <- predictions.assay

DefaultAssay(breast_cancer) <- "predictions"

Let’s have a look at our annotations again.

ca <- readbitmap::read.bitmap("images/Breast Cancer Path.png")
# in the tutorial
# ca <- readbitmap::read.bitmap('/mnt/libs/shared_data/human_breast_cancer_1/images/Breast_Cancer_Path.png')
plot(0:1,0:1,type="n",ann=FALSE,axes=FALSE)
rasterImage(ca,0,0,1,1)

Immune Microenvironment

T cell subtypes

What about the immune microenvironment?

Ducal Carcinoma in situ is depleted of T-cells

(SpatialFeaturePlot(breast_cancer, 
                   features = c("T cells-0"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE) |
SpatialFeaturePlot(breast_cancer, 
                   features = c("T cells-1"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE)) /
(SpatialFeaturePlot(breast_cancer, 
                   features = c("T cells-2"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE) |
SpatialFeaturePlot(breast_cancer, 
                   features = c("T cells-5"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE))

B cell subtypes

B cells are enriched in the fibrous tissue outside the tumor

SpatialFeaturePlot(breast_cancer, 
                   features = c("B cells"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE)

There seem to be some ductal cells but have a look at our score. Are we confident in this assertion?

SpatialFeaturePlot(breast_cancer, 
                   features = c("Ductal cells"), 
                   pt.size.factor = 1.5,  crop = TRUE)

Tumor Subtypes

It looks like the ducal carcinoma in situ is enriched for tumor subtypes 8, 10, and 12 but not 3.

(SpatialFeaturePlot(breast_cancer, 
                   features = c("Tumor cells-3"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE) |
SpatialFeaturePlot(breast_cancer, 
                   features = c("Tumor cells-8"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE)) /
(SpatialFeaturePlot(breast_cancer, 
                   features = c("Tumor cells-10"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE) |
SpatialFeaturePlot(breast_cancer, 
                   features = c("Tumor cells-12"), 
                   pt.size.factor = 1.5, ncol = 2, crop = TRUE))

Like the Ductal Cells, we might not be as confident in the Tumor Stem Cells but this might make sense considering the 10x snRNA dataset and the Visium dataset are from different individuals.

SpatialFeaturePlot(breast_cancer, 
                   features = c("CD49f-hi MaSCs"), 
                   pt.size.factor = 1.5,crop = TRUE) + 
plot_annotation(
  title = 'Tumor Stem Cells')

LS0tCnRpdGxlOiAiU0lCIERheXMgMjAyMCAtIFZpcnR1YWwgQ29uZmVyZW5jZSAtIEp1bmUgOCwgMjAyMCIKc3VidGl0bGU6ICJEYXRhc2V0OiBCcmVhc3QgQ2FuY2VyIgphdXRob3I6CiAgLSBQYXRyaWNrIFJvZWxsaSwgQ29tcHV0YXRpb25hbCBCaW9sb2dpc3QgMiAtIENvbXB1dGF0aW9uYWwgQmlvbG9neV5bMTB4IEdlbm9taWNzLCBwYXRyaWNrLnJvZWxsaUAxMHhnZW5vbWljcy5jb20gXQogIC0gU3RlZmFuaWEgR2lhY29tZWxsbywgQ29tcHV0YXRpb25hbCBCaW9sb2dpc3QgMiAtIENvbXB1dGF0aW9uYWwgQmlvbG9neV5bMTB4IEdlbm9taWNzLCBzdGVmYW5pYS5naWFjb21lbGxvQDEweGdlbm9taWNzLmNvbV0KICAtIFN0ZXBoZW4gV2lsbGlhbXMsIFNlbmlvciBTY2llbnRpc3QgLSBDb21wdXRhdGlvbmFsIEJpb2xvZ3leWzEweCBHZW5vbWljcywgc3RlcGhlbi53aWxsaWFtc0AxMHhnZW5vbWljcy5jb21dCmRhdGU6ICdMYXN0IENvbXBpbGVkOiBgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIHRoZW1lOiBqb3VybmFsCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KClshWzEweCBIb21lXShodHRwczovL2dpdGh1Yi5jb20vc3RlcGhlbndpbGxpYW1zMjIvU0lCXzIwMjBfV29ya3Nob3AvcmF3L21hc3Rlci9pbWFnZXMvMTB4JTIwaG9tZXBhZ2UucG5nKV0oaHR0cHM6Ly93d3cuMTB4Z2Vub21pY3MuY29tLykKCiMgKipJbnRyb2R1Y3Rpb24qKgoKV2VsY29tZSB0byB0aGUgKipTSUIgRGF5cyAyMDIwIC0gdmlydHVhbCBjb25mZXJlbmNlKiogU3BhdGlhbCBUcmFuc2NyaXB0b21pY3Mgd29ya3Nob3AgYnkgMTB4IGdlbm9taWNzIQoKVGhlIHB1cnBvc2Ugb2YgdGhpcyB0dXRvcmlhbCB3aWxsIGJlIHRvIHdhbGsgdXNlcnMgdGhyb3VnaCBzb21lIG9mIHRoZSBzdGVwcyBuZWNlc3NhcnkgdG8gZXhwbG9yZSBkYXRhIHByb2R1Y2VkIGJ5IHRoZSAxMHggR2Vub21pY3MgVmlzaXVtIFNwYXRpYWwgR2VuZSBFeHByZXNzaW9uIFNvbHV0aW9uIGFuZCB0aGUgW1NwYWNlcmFuZ2VyIHBpcGVsaW5lXShodHRwczovL3N1cHBvcnQuMTB4Z2Vub21pY3MuY29tL3NwYXRpYWwtZ2VuZS1leHByZXNzaW9uL3NvZnR3YXJlL3BpcGVsaW5lcy9sYXRlc3Qvd2hhdC1pcy1zcGFjZS1yYW5nZXIpLiBXZSB3aWxsIGludmVzdGlnYXRlIHRoZSBkYXRhIHNldHMgIGFyZSBhbGwgZnJlZWx5IGF2YWlsYWJsZSBmcm9tIFsxMHggR2Vub21pY3NdKGh0dHBzOi8vc3VwcG9ydC4xMHhnZW5vbWljcy5jb20vc3BhdGlhbC1nZW5lLWV4cHJlc3Npb24vZGF0YXNldHMpLgoKW1NldXJhdCBUdXRvcmlhbF0oaHR0cHM6Ly9zYXRpamFsYWIub3JnL3NldXJhdC92My4xL3NwYXRpYWxfdmlnbmV0dGUuaHRtbCkKCioqVGhpbmdzIHRvIGtub3cgYWJvdXQgdGhpcyB3b3Jrc2hvcCoqCgoxLiBBbGwgZmlsZXMgdGhhdCB3aWxsIGJlIHVzZWQgY2FuIGJlIGZvdW5kIGF0OiBgL21udC9saWJzL3NoYXJlZF9kYXRhL2AKClshW1Rlcm1pbmFsXShodHRwczovL2dpdGh1Yi5jb20vc3RlcGhlbndpbGxpYW1zMjIvU0lCXzIwMjBfV29ya3Nob3AvcmF3L21hc3Rlci9pbWFnZXMvVGVybWluYWwucG5nKV0KCjIuIEdldHRpbmcgc3RhcnRlZCB3aXRoIFIgYW5kIFZpc2l1bSBkYXRhIG91dHNpZGUgb2YgU2V1cmF0IGF0OiBodHRwczovL3N1cHBvcnQuMTB4Z2Vub21pY3MuY29tL3NwYXRpYWwtZ2VuZS1leHByZXNzaW9uL3NvZnR3YXJlL3BpcGVsaW5lcy9sYXRlc3QvcmtpdAozLiBSZWZlcmVuY2UgZ2Vub21lIGZvciBhbGwgc2FtcGxlcyBpcyBHUkNoMzgvbW0xMAo0LiBBbGwgMTB4IHNvZnR3YXJlIGluY2x1ZGluZyBbU3BhY2VyYW5nZXJdKGh0dHBzOi8vc3VwcG9ydC4xMHhnZW5vbWljcy5jb20vc3BhdGlhbC1nZW5lLWV4cHJlc3Npb24vc29mdHdhcmUvcGlwZWxpbmVzL2xhdGVzdC93aGF0LWlzLXNwYWNlLXJhbmdlciksIGFuZCBbTG91cGUgQnJvd3Nlcl0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zcGF0aWFsLWdlbmUtZXhwcmVzc2lvbi9zb2Z0d2FyZS92aXN1YWxpemF0aW9uL2xhdGVzdC93aGF0LWlzLWxvdXBlLWJyb3dzZXIpLCBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIHRoZSBbMTB4IFN1cHBvcnQgU2l0ZV0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS8pCjUuIE1vc3QgU2V1cmF0IGZpZ3VyZXMgY2FuIGJlIGNvbnRyb2xsZWQgd2l0aCBwYXRjaHdvcmsgYmVjYXVzZSB0aGV5IGFyZSBmdW5kYW1lbnRhbGx5IGdncGxvdCBvYmplY3RzLiBTb21lIHJlYWxseSBuaWNlIGV4YW1wbGVzIGNhbiBiZSBmb3VuZCBvbiB0aGUgW1BhdGNod29yayBHaXRIdWJdKGh0dHBzOi8vcGF0Y2h3b3JrLmRhdGEtaW1hZ2luaXN0LmNvbS9hcnRpY2xlcy9ndWlkZXMvbGF5b3V0Lmh0bWwpCgoKIyAqKkV4cGxvcmluZyBWaXNpdW0gRGF0YSB3aXRoIFNldXJhdCoqCgojIyBMb2FkIG91ciBwYWNrYWdlcwpgYGB7ciBMaWJyYXJpZXMsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCiMjIExvYWRpbmcgZGF0YSBpbiBhIFNldXJhdCBvYmplY3QKClJlYWwgRGF0YXNldCBmb3IgdGhlIHR1dG9yaWFsCmBgYHtyIGV2YWw9RkFMU0V9CmJyZWFzdF9jYW5jZXIgPC0gTG9hZDEwWF9TcGF0aWFsKGRhdGEuZGlyID0gIi9tbnQvbGlicy9zaGFyZWRfZGF0YS9odW1hbl9icmVhc3RfY2FuY2VyXzEvb3V0cy8iLAogICAgICAgICAgICAgICAgZmlsZW5hbWUgPSAiVjFfQnJlYXN0X0NhbmNlcl9CbG9ja19BX1NlY3Rpb25fMV9maWx0ZXJlZF9mZWF0dXJlX2JjX21hdHJpeC5oNSIpCmBgYAoKClNhbWUgZGF0YSBqdXN0IGludGVybmFsIHRvIDEweApgYGB7cn0KYnJlYXN0X2NhbmNlciA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSAiL21udC9hbmFseXNpcy9tYXJzb2MvcGlwZXN0YW5jZXMvSFdIVEZEU1hYL1NQQVRJQUxfUk5BX0NPVU5URVJfUEQvMTYzMDg2L0hFQUQvb3V0cy8iLCBzbGljZSA9ICJzbGljZTEiKQpgYGAKClRoZXJlIGFyZSBhIGJ1bmNoIG9mIGRhdGEgc2V0cyBob3N0ZWQgYnkgdGhlIFNhdGlqYSBsYWIgaW4gdGhlIFtTZXVyYXQgRGF0YSBQYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vc2F0aWphbGFiL3NldXJhdC1kYXRhKS4KCiMgKipSZXN1bHRzKioKIyMgUUMKTGV0J3MgaGF2ZSBhIGxvb2sgYXQgc29tZSBiYXNpYyBRQyBpbmZvcm1hdGlvbi4gS2VlcCBpbiBtaW5kIHRoYXQgbW9zdCBTZXVyYXQgcGxvdHMgYXJlIGdncGxvdCBvYmplY3QgYW5kIGNhbiBiZSBtYW5pcHVsYXRlZCBhcyBzdWNoLgoKQ291bnRzID0gVU1JCkZlYXR1cmVzID0gR2VuZXMKYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTgsIHdhcm5pbmc9RkFMU0V9CnBsb3QxIDwtIFZsblBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSAibkNvdW50X1NwYXRpYWwiLCBwdC5zaXplID0gMC4xKSArIAogIGdndGl0bGUoIlVNSSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgTm9MZWdlbmQoKQoKcGxvdDIgPC0gVmxuUGxvdChicmVhc3RfY2FuY2VyLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9TcGF0aWFsIiwgcHQuc2l6ZSA9IDAuMSkgKyAKICBnZ3RpdGxlKCJHZW5lcyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgTm9MZWdlbmQoKQoKcGxvdDMgPC0gU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIGZlYXR1cmVzID0gIm5Db3VudF9TcGF0aWFsIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKcGxvdDQgPC0gU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1NwYXRpYWwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikKCnBsb3QxICsgcGxvdDIgKyBwbG90MyAgKyBwbG90NCArIHBsb3RfbGF5b3V0KG5yb3cgPSAyLCBuY29sID0gMikKYGBgCgojIyBOb3JtYWxpemF0aW9uCgpTcGFjZXJhbmdlciBkb2VzIG5vcm1hbGl6YXRpb24gZm9yIGNsdXN0ZXJpbmcgYW5kIERFIGJ1dCBkb2VzIG5vdCByZXR1cm4gdGhhdCBub3JtYWxpemVkIG1hdHJpeAoKUHJlLW5vcm1hbGl6YXRpb24gClJhdyBVTUkgY291bnRzCmBgYHtyLCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCBmZWF0dXJlcyA9IGMoIkVSQkIyIiwgIkNEOEEiKSkKYGBgCgojIyMgU0UgdHJhbnNmb3JtCgorICBUaGlzIHdpbGwgdGFrZSB+My00IG1pbi4gCgpEb24ndCB3b3JyeSBhYm91dCBgcmVhY2hlZGl0ZXJhdGlvbiBsaW1pdGAgd2FybmluZ3MuIFNlZSBodHRwczovL2dpdGh1Yi5jb20vQ2hyaXN0b3BoSC9zY3RyYW5zZm9ybS9pc3N1ZXMvMjUgZm9yIGRpc2N1c3Npb24KCkRlZmF1bHQgYXNzYXkgd2lsbCBub3cgYmUgc2V0IHRvIFNDVApgYGB7ciwgd2FybmluZz1GQUxTRX0KYnJlYXN0X2NhbmNlciA8LSBTQ1RyYW5zZm9ybShicmVhc3RfY2FuY2VyLCBhc3NheSA9ICJTcGF0aWFsIiwgdmVyYm9zZSA9IEZBTFNFKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQpTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSBjKCJFUkJCMiIsICJDRDhBIikpCmBgYAoKCkZyb20gU2V1cmF0OiAKClRoZSBkZWZhdWx0IHBhcmFtZXRlcnMgaW4gU2V1cmF0IGVtcGhhc2l6ZSB0aGUgdmlzdWFsaXphdGlvbiBvZiBtb2xlY3VsYXIgZGF0YS4gSG93ZXZlciwgeW91IGNhbiBhbHNvIGFkanVzdCB0aGUgc2l6ZSBvZiB0aGUgc3BvdHMgKGFuZCB0aGVpciB0cmFuc3BhcmVuY3kpIHRvIGltcHJvdmUgdGhlIHZpc3VhbGl6YXRpb24gb2YgdGhlIGhpc3RvbG9neSBpbWFnZSwgYnkgY2hhbmdpbmcgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzOgoKICAgIHB0LnNpemUuZmFjdG9yLSBUaGlzIHdpbGwgc2NhbGUgdGhlIHNpemUgb2YgdGhlIHNwb3RzLiBEZWZhdWx0IGlzIDEuNgogICAgYWxwaGEgLSBtaW5pbXVtIGFuZCBtYXhpbXVtIHRyYW5zcGFyZW5jeS4gRGVmYXVsdCBpcyBjKDEsIDEpLgogICAgVHJ5IHNldHRpbmcgdG8gYWxwaGEgYygwLjEsIDEpLCB0byBkb3dud2VpZ2h0IHRoZSB0cmFuc3BhcmVuY3kgb2YgcG9pbnRzIHdpdGggbG93ZXIgZXhwcmVzc2lvbgoKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQpwMSA8LSBTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSAiSUdGQlA1IiwgcHQuc2l6ZS5mYWN0b3IgPSAxKSsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIGdndGl0bGUoIkFjdHVhbCBTcG90IFNpemUiKQpwMiA8LSBTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSAiSUdGQlA1IikrIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICBnZ3RpdGxlKCJTY2FsZWQgU3BvdCBTaXplIikKcDEgKyBwMgpgYGAKCiMjIyBEaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24sIGNsdXN0ZXJpbmcsIGFuZCB2aXN1YWxpemF0aW9uCgpXZSBjYW4gdGhlbiBwcm9jZWVkIHRvIHJ1biBkaW1lbnNpb25hbGl0eSByZWR1Y3Rpb24gYW5kIGNsdXN0ZXJpbmcgb24gdGhlIFJOQSBleHByZXNzaW9uIGRhdGEsIHVzaW5nIHRoZSBzYW1lIHdvcmtmbG93IGFzIHdlIHVzZSBmb3Igc2NSTkEtc2VxIGFuYWx5c2lzLgoKU29tZSBvZiB0aGVzZSBwcm9jZXNzZXMgY2FuIGJlIHBhcmFsbGl6ZWQKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KbGlicmFyeShmdXR1cmUpCiMgY2hlY2sgdGhlIGN1cnJlbnQgYWN0aXZlIHBsYW4KcGxhbigpCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQojIGNoYW5nZSB0aGUgY3VycmVudCBwbGFuIHRvIGFjY2VzcyBwYXJhbGxlbGl6YXRpb24KcGxhbigibXVsdGlwcm9jZXNzIiwgd29ya2VycyA9IDQpCnBsYW4oKQpgYGAKCgpUaGUgZGVmYXVsdCBVTUFQIGNhbGN1bGF0aW9uIGlzIHBlcmZvcm1lZCB3aXRoIHRoZSBbUi1iYXNlZCBVV09UXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdXdvdC9pbmRleC5odG1sKSBsaWJyYXJ5IEhvd2V2ZXIsIHlvdSBjYW4gcnVuIFVNQVAgaW4gcHl0aG9uIHZpYSByZXRpY3VsYXRlIGxpYnJhcnkgYW5kIGB1bWFwLWxlYXJuYC4gV2UgaGF2ZSBmb3VuZCB0aGF0IGZvciBzbWFsbGVyIGRhdGEgc2V0cyAoPD0gMTBrIGNlbGxzL3Nwb3RzKSBVV09UIGlzIGdyZWF0LiBGb3IgbXVjaCBsYXJnZXIgZGF0YSBzZXRzICgxMDBrICsgY2VsbHMvc3BvdHMpIGB1bWFwLWxlYXJuYCBjYW4gYmUgYSBmYXN0ZXIgb3B0aW9uLgoKYGBge3J9CmJyZWFzdF9jYW5jZXIgPC0gUnVuUENBKGJyZWFzdF9jYW5jZXIsIGFzc2F5ID0gIlNDVCIsIHZlcmJvc2UgPSBGQUxTRSkKYnJlYXN0X2NhbmNlciA8LSBGaW5kTmVpZ2hib3JzKGJyZWFzdF9jYW5jZXIsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMTozMCkKYnJlYXN0X2NhbmNlciA8LSBGaW5kQ2x1c3RlcnMoYnJlYXN0X2NhbmNlciwgdmVyYm9zZSA9IEZBTFNFKQpicmVhc3RfY2FuY2VyIDwtIFJ1blVNQVAoYnJlYXN0X2NhbmNlciwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjMwKQpgYGAKCk5vdyBsZXQncyBoYXZlIGEgbG9vayBhdCB0aGUgY2x1c3RlcmluZwoKYGBge3IsIGZpZy53aWR0aD04fQpEaW1QbG90KGJyZWFzdF9jYW5jZXIsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBGQUxTRSwpICsKICBsYWJzKGNvbG9yID0gIkNsdXN0ZXIiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMCwgd2FybmluZz1GQUxTRX0KcDEgPC0gRGltUGxvdChicmVhc3RfY2FuY2VyLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSkgKwogIGxhYnMoY29sb3IgPSAiQ2x1c3RlciIpCnAyIDwtIFNwYXRpYWxEaW1QbG90KGJyZWFzdF9jYW5jZXIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMpICsKICBsYWJzKGZpbGwgPSAiQ2x1c3RlciIpCgpwMSArIHAyICsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ0NsdXN0ZXJpbmcgaW4gVU1BUCBhbmQgVGlzc3VlIFNwYWNlJywKICBjYXB0aW9uID0gJ1Byb2Nlc3NlZCBieSBTcGFjZXJhbmdlciAxLjFcbk5vcm1pbGl6YXRpb24gYW5kIENsdXN0ZXJpbmcgYnkgU2V1cmF0JwopICsgcGxvdF9sYXlvdXQobnJvdyA9IDEpCmBgYAoKSSBkb24ndCByZWFsbHkgbGlrZSB0aGVzZSBjb2xvcnMgc28gbGV0J3MgY2hhbmdlIHRoZW0KYGBge3J9Cm15UGFsZXR0ZSA8LSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKDExLCAiU3BlY3RyYWwiKSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgd2FybmluZz1GQUxTRX0KcDEgPC0gRGltUGxvdChicmVhc3RfY2FuY2VyLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSkgKwogIGxhYnMoY29sb3IgPSAiQ2x1c3RlciIpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNiMmRmOGEiLCIjZTQxYTFjIiwiIzM3N2ViOCIsIiM0ZGFmNGEiLCIjZmY3ZjAwIiwiZ29sZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNhNjU2MjgiLCAiIzk5OTk5OSIsICJibGFjayIsICJwaW5rIiwgInB1cnBsZSIsICJicm93biIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3JleSIsICJ5ZWxsb3ciLCAiZ3JlZW4iKSkKCnAyIDwtIFNwYXRpYWxEaW1QbG90KGJyZWFzdF9jYW5jZXIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDMpICsKICBsYWJzKGZpbGwgPSAiQ2x1c3RlciIpKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjJkZjhhIiwiI2U0MWExYyIsIiMzNzdlYjgiLCIjNGRhZjRhIiwiI2ZmN2YwMCIsImdvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjYTY1NjI4IiwgIiM5OTk5OTkiLCAiYmxhY2siLCAicGluayIsICJwdXJwbGUiLCAiYnJvd24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyZXkiLCAieWVsbG93IiwgImdyZWVuIikpCgpwMSArIHAyICsgcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ0NsdXN0ZXJpbmcgaW4gVU1BUCBhbmQgVGlzc3VlIFNwYWNlJywKICBjYXB0aW9uID0gJ1Byb2Nlc3NlZCBieSBTcGFjZXJhbmdlciAxLjFcbk5vcm1pbGl6YXRpb24gYW5kIENsdXN0ZXJpbmcgYnkgU2V1cmF0JwopICsgcGxvdF9sYXlvdXQobnJvdyA9IDEpCmBgYAoKSWYgaW50ZXJlc3RlZCB5b3UgY2FuIGFsc28gbm93IGxvb2sgYXQgVU1JIGFuZCBHZW5lIGNvdW50cyBwZXIgY2x1c3RlciBhcyB3ZWxsCmBgYHtyfQpwbG90MSA8LSBWbG5QbG90KGJyZWFzdF9jYW5jZXIsIGZlYXR1cmVzID0gIm5Db3VudF9TcGF0aWFsIiwgcHQuc2l6ZSA9IDAuMSkgKyAKICBnZ3RpdGxlKCJVTUkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IyZGY4YSIsIiNlNDFhMWMiLCIjMzc3ZWI4IiwiIzRkYWY0YSIsIiNmZjdmMDAiLCJnb2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2E2NTYyOCIsICIjOTk5OTk5IiwgImJsYWNrIiwgInBpbmsiLCAicHVycGxlIiwgImJyb3duIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmV5IiwgInllbGxvdyIsICJncmVlbiIpKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArCiAgTm9MZWdlbmQoKQoKcGxvdDIgPC0gVmxuUGxvdChicmVhc3RfY2FuY2VyLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9TcGF0aWFsIiwgcHQuc2l6ZSA9IDAuMSkgKyAKICBnZ3RpdGxlKCJHZW5lcyIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjYjJkZjhhIiwiI2U0MWExYyIsIiMzNzdlYjgiLCIjNGRhZjRhIiwiI2ZmN2YwMCIsImdvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjYTY1NjI4IiwgIiM5OTk5OTkiLCAiYmxhY2siLCAicGluayIsICJwdXJwbGUiLCAiYnJvd24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyZXkiLCAieWVsbG93IiwgImdyZWVuIikpKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKwogIE5vTGVnZW5kKCkKCnBsb3QxICsgcGxvdDIKYGBgCgoKTm93IGxldCdzIHRha2UgYSBsb29rIGF0IGF0IGEgZ2VuZSBvZiBpbnRlcmVzdCB3aXRoIHZpb2xpbiBwbG90cyBidXQgYWxzbyBpbiBpbWFnZSBzcGFjZS4KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTh9CnAxIDwtIFZsblBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSAiSUdGQlA1IiwgcHQuc2l6ZSA9IDAuMSkgKyAKICBnZ3RpdGxlKCJJR0ZCUDUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IyZGY4YSIsIiNlNDFhMWMiLCIjMzc3ZWI4IiwiIzRkYWY0YSIsIiNmZjdmMDAiLCJnb2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2E2NTYyOCIsICIjOTk5OTk5IiwgImJsYWNrIiwgInBpbmsiLCAicHVycGxlIiwgImJyb3duIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmV5IiwgInllbGxvdyIsICJncmVlbiIpKSsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsKICBOb0xlZ2VuZCgpICsKICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9MjMsIHNpemU9NCwgY29sb3I9InJlZCIpCgpwMiA8LSBTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSAiSUdGQlA1IikrIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpwMyA8LSBTcGF0aWFsRGltUGxvdChicmVhc3RfY2FuY2VyLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSAzKSArCiAgbGFicyhmaWxsID0gIkNsdXN0ZXIiKSsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2IyZGY4YSIsIiNlNDFhMWMiLCIjMzc3ZWI4IiwiIzRkYWY0YSIsIiNmZjdmMDAiLCJnb2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2E2NTYyOCIsICIjOTk5OTk5IiwgImJsYWNrIiwgInBpbmsiLCAicHVycGxlIiwgImJyb3duIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmV5IiwgInllbGxvdyIsICJncmVlbiIpKSArCiAgTm9MZWdlbmQoKQoKcm93MSA8LSBwMiArIHAzICsgcGxvdF9sYXlvdXQobnJvdyA9IDEpCnJvdzEgKyBwMSsgcGxvdF9sYXlvdXQobnJvdyA9IDIsIHdpZHRocyA9IGMoMC41LCAwLjUpKQpgYGAKCldlIGNhbiBhbHNvIGxvb2sgYXQgdGhlc2UgZGF0YSBpbnRlcmFjdGl2ZWx5CmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KTGlua2VkRGltUGxvdChicmVhc3RfY2FuY2VyKQpgYGAKCiMjIFNwYXRpYWxseSB2YXJpYWJsZSBmZWF0dXJlcwoKRmlyc3Qgd2UnbGwgaWRlbnRpZnkgZGVmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMuIAoKUGFyYWxsZWxpemF0aW9uIGhlbHBzIGhlcmUgdG9vIGxldCdzIG1ha2Ugc3VyZSBvdXIgcGxhbiBpcyBzdGlsbCBpbnRhY3QKCmBgYHtyLCBldmFsPUZBTEUsIGluY2x1ZGU9VFJVRX0KcGxhbigpCmBgYAoKCkxldCdzIGZpbmQgYWxsIHRoZSBtYXJrZXJzIGZvciBldmVyeSBjbHVzdGVyCmBgYHtyfQpkZV9tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKGJyZWFzdF9jYW5jZXIsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCgpkZV9tYXJrZXJzICU+JQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3BfbihuID0gMiwgd3QgPSBhdmdfbG9nRkMpCmBgYAoKIyMgSWRlbnRpZnkgdGhlIG1vc3QgdXAtcmVndWxhdGVkIGFuZCBkb3duLXJlZ3VsYXRlZCBnZW5lcwpgYGB7cn0KZGVfbWFya2Vyc191cCA8LSBkZV9tYXJrZXJzICU+JQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJHZW5lIikgJT4lIAogIGFycmFuZ2UoLWF2Z19sb2dGQykKCmRlX21hcmtlcnNfZG93biA8LSBkZV9tYXJrZXJzICU+JQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJHZW5lIikgJT4lIAogIGFycmFuZ2UoYXZnX2xvZ0ZDKQpgYGAKCmBgYHtyfQpkZV9tYXJrZXJzX3VwCmBgYAoKYGBge3J9CmRlX21hcmtlcnNfZG93bgpgYGAKCiMjIyBNb3N0IHVwLXJlZ3VsYXRlZCBnZW5lcwpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCB3YXJuaW5nPUZBTFNFfQpTcGF0aWFsRmVhdHVyZVBsb3Qob2JqZWN0ID0gYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSBkZV9tYXJrZXJzX3VwJEdlbmVbMToxMF0sIGFscGhhID0gYygwLjEsIDEpLCBuY29sID0gMykKYGBgCgojIyMgTW9zdCBkb3duLXJlZ3VsYXRlZCBnZW5lcwpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCB3YXJuaW5nPUZBTFNFfQpTcGF0aWFsRmVhdHVyZVBsb3Qob2JqZWN0ID0gYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSBkZV9tYXJrZXJzX2Rvd24kR2VuZVsxOjEwXSwgYWxwaGEgPSBjKDAuMSwgMSksIG5jb2wgPSAzKQpgYGAKCndoYXQgYXJlIHRoZSB0b3AgdmFyaWFibGUgZmVhdHVyZXM/CmBgYHtyfQpWYXJpYWJsZUZlYXR1cmVzKGJyZWFzdF9jYW5jZXIpWzE6MTBdCmBgYAoKd2hhdCBhcmUgdGhlIHRvcCBERSBnZW5lcz8KYGBge3J9CnJvd25hbWVzKGRlX21hcmtlcnMpWzE6MTBdCmBgYAoKIyMgU3BhdGlhbGx5IFZhcmlhYmxlIEdlbmVzCgpTbyB3aGF0IGFib3V0IHNwYXRpYWwgZW5yaWNobWVudD8gCgpTb21lIG1ldGhvZHMKCjEuIFtUcmVuZHNjZWVrXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL25tZXRoLjQ2MzQpCjIuIFtTcGxvdGNoXShodHRwczovL3d3dy5iaW9yeGl2Lm9yZy9jb250ZW50LzEwLjExMDEvNzU3MDk2djEpCjMuIFtTUEFSS10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1OTItMDE5LTA3MDEtNykKNC4gW1NwYXRpYWxERV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC40NjM2KQogICsgV2UgaGF2ZSBmb3VuZCB0aGlzIGltcGxlbWVudGF0aW9uIG5vdCB0byBiZSB2ZXJ5IGVmZmVjdGl2ZS4gSXQncyBhbHNvIG5vdCB1bmRlciBhY3RpdmUgZGV2ZWxvcG1lbnQKCgpVc2luZyB0aGUgdG9wIDEwMCB2YXJpYWJsZSBnZW5lcyBmaW5kIHNwYXRpYWxseSBlbnJpY2hlZCBvbmVzLiBOb3RlIHRoYXQgaW4gdGhlIFNldXJhdCBTcGF0aWFsIFR1dG9yaWFsIHRoZXkgdXNlIDEwMDAgZ2VuZXMuIFlvdSBjYW4gYWxzbyB1c2UgYWxsIGdlbmVzIGJ1dCB0aGF0IHdpbGwgdGFrZSBhIGxvbmcgdGltZS4gVXNpbmcgYSBjYWxjdWxhdGlvbiBvZiBbTW9yYW5zIEldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01vcmFuJTI3c19JKSBjYW4gc29tZXRpbWVzIGJlIGEgZmFzdGVyIGFwcHJvYWNoLCBlc3BlY2lhbGx5IGlmIHlvdSBhcmUgdXNpbmcgcGFyYWxsaXphdGlvbi4KCgpgYGB7cn0KYnJlYXN0X2NhbmNlciA8LSBGaW5kU3BhdGlhbGx5VmFyaWFibGVGZWF0dXJlcyhicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYnJlYXN0X2NhbmNlcilbMToxMDBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbi5tZXRob2QgPSAibWFya3ZhcmlvZ3JhbSIsIHZlcmJvc2UgPSBUUlVFKQpgYGAKCkhhdmUgYSBsb29rIGF0IHRoZSBzcGF0aWFsbHkgdmFyaWFibGUgZ2VuZXMgY2FsY3VsYXRlZCBieSBgbWFya3ZhcmlvZ3JhbWAgb3JkZXJlZCBmcm9tIG1vc3QgdmFyaWFibGUgdG8gbGVhc3QgdmFyaWFibGUKYGBge3J9ClNwYXRpYWxseVZhcmlhYmxlRmVhdHVyZXMoYnJlYXN0X2NhbmNlciwgc2VsZWN0aW9uLm1ldGhvZCA9ICJtYXJrdmFyaW9ncmFtIiwgZGVjcmVhc2luZyA9IFRSVUUpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04LCB3YXJuaW5nPUZBTFNFfQp0b3AuZmVhdHVyZXNfdHJlbmRzZXEgPC0gaGVhZChTcGF0aWFsbHlWYXJpYWJsZUZlYXR1cmVzKGJyZWFzdF9jYW5jZXIsIHNlbGVjdGlvbi5tZXRob2QgPSAibWFya3ZhcmlvZ3JhbSIpLCA4KQpTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSB0b3AuZmVhdHVyZXNfdHJlbmRzZXEsIG5jb2wgPSA0LCBhbHBoYSA9IGMoMC4xLCAxKSkKYGBgCgpNb3JhbidzIEkgaW1wbGVtZW50YXRpb24uIEZvciBvdGhlciBzcGF0aWFsIGRhdGEgdHlwZXMgdGhlIHguY3V0cyBhbmQgeS5jdXRzIGRldGVybWluZXMgdGhlIGdyaWQgdGhhdCBpcyBsYWlkIG92ZXIgdGhlIHRpc3N1ZSBpbiB0aGUgY2FwdHVyZSBhcmVhLiBIZXJlIHdlJ2xsIHJlbW92ZSB0aG9zZQpgYGB7cn0KYnJlYXN0X2NhbmNlciA8LSBGaW5kU3BhdGlhbGx5VmFyaWFibGVGZWF0dXJlcyhicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhc3NheSA9ICJTQ1QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90ID0gInNjYWxlLmRhdGEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMoYnJlYXN0X2NhbmNlcilbMToxMDBdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvbi5tZXRob2QgPSAibW9yYW5zaSIpCmBgYAoKCkhhdmUgYSBsb29rIGF0IHRoZSBzcGF0aWFsbHkgdmFyaWFibGUgZ2VuZXMgY2FsY3VsYXRlZCBieSBgbW9yYW5zaWAgb3JkZXJlZCBmcm9tIG1vc3QgdmFyaWFibGUgdG8gbGVhc3QgdmFyaWFibGUKCmBgYHtyfQpTcGF0aWFsbHlWYXJpYWJsZUZlYXR1cmVzKGJyZWFzdF9jYW5jZXIsIHNlbGVjdGlvbi5tZXRob2QgPSAibW9yYW5zaSIsIGRlY3JlYXNpbmcgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OCwgd2FybmluZz1GQUxTRX0KdG9wLmZlYXR1cmVzX21vcmFuc2kgPC0gaGVhZChTcGF0aWFsbHlWYXJpYWJsZUZlYXR1cmVzKGJyZWFzdF9jYW5jZXIsIHNlbGVjdGlvbi5tZXRob2QgPSAibW9yYW5zaSIpLCA4KQpTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgZmVhdHVyZXMgPSB0b3AuZmVhdHVyZXNfbW9yYW5zaSwgbmNvbCA9IDQsIGFscGhhID0gYygwLjEsIDEpKQpgYGAKCldlIGNhbiBzZWUgdGhhdCB0aGUgcmVzdWx0cyBhcmUgc2xpZ2h0bHkgZGlmZmVyZW50LiBTbyBsZXQncyB0YWtlIGEgbG9vayBhdCB3aHkuCgpgYGB7cn0Kc3BhdGlhbGx5X3ZhcmlhYmxlX2dlbmVzIDwtIGJyZWFzdF9jYW5jZXJAYXNzYXlzJFNDVEBtZXRhLmZlYXR1cmVzICU+JQogIHRpZHlyOjpkcm9wX25hKCkKCnNwYXRpYWxseV92YXJpYWJsZV9nZW5lcwpgYGAKWW91IGNhbiBzZWUgdGhlIHR3byBtZXRob2RzIHNob3cgCmBgYHtyfQptbV9jb3IgPC0gY29yLnRlc3Qoc3BhdGlhbGx5X3ZhcmlhYmxlX2dlbmVzJG1vcmFuc2kuc3BhdGlhbGx5LnZhcmlhYmxlLnJhbmssIHNwYXRpYWxseV92YXJpYWJsZV9nZW5lcyRtYXJrdmFyaW9ncmFtLnNwYXRpYWxseS52YXJpYWJsZS5yYW5rKQpnZ3Bsb3Qoc3BhdGlhbGx5X3ZhcmlhYmxlX2dlbmVzLCBhZXMoeD1tb3JhbnNpLnNwYXRpYWxseS52YXJpYWJsZS5yYW5rLHk9bWFya3ZhcmlvZ3JhbS5zcGF0aWFsbHkudmFyaWFibGUucmFuaykpKwogIGdlb21fcG9pbnQoKSsKICBnZW9tX3Ntb290aCgpKwogIHhsYWIoIk1vcmFucyBJIFJhbmsiKSsKICB5bGFiKCJNYXJrdmFyaW9ncmFtIFJhbmsiKSsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAyNSwgeSA9IDc1LCBsYWJlbCA9IHBhc3RlKCJQZWFyc29uJ3MgQ29ycmVsYXRpb25cbiIsIHJvdW5kKG1tX2NvciRlc3RpbWF0ZVsxXSwgZGlnaXRzID0gMiksIHNlcCA9ICIiKSkrCiAgdGhlbWVfYncoKQpgYGAKCiMjIENhbmNlciBhbm5vdGF0aW9ucwoKV2hlcmUgYXJlIHRoZXNlIGdlbmVzIGJlaW5nIGV4cHJlc3NlZCByZWxhdGl2ZSB0byBwYXRob2xvZ2lzdCBhbm5vdGF0aW9uPwoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9CmNhIDwtIHJlYWRiaXRtYXA6OnJlYWQuYml0bWFwKCJpbWFnZXMvQnJlYXN0IENhbmNlciBQYXRoLnBuZyIpCiMgaW4gdGhlIHR1dG9yaWFsCiMgY2EgPC0gcmVhZGJpdG1hcDo6cmVhZC5iaXRtYXAoJy9tbnQvbGlicy9zaGFyZWRfZGF0YS9odW1hbl9icmVhc3RfY2FuY2VyXzEvaW1hZ2VzL0JyZWFzdF9DYW5jZXJfUGF0aC5wbmcnKQpwbG90KDA6MSwwOjEsdHlwZT0ibiIsYW5uPUZBTFNFLGF4ZXM9RkFMU0UpCnJhc3RlckltYWdlKGNhLDAsMCwxLDEpCmBgYAoKTG9va3MgbGlrZSB0aGUgIE1hdHJpeCBHbGEgcHJvdGVpbiAoIF9NR1BfICkgZ2VuZSBpcyBlbnJpY2hlZCBpbiBEdWN0YWwgQ2FyY2lub21hIF9JbiBTaXR1Xy4gTm90IGEgbG90IGlzIGtub3duIGFib3V0IF9NR1BfIGluIHRoZSBjb250ZXh0IG9mIGNhbmNlciBidXQgaXQgbG9va3MgbGlrZSBpdCBjb3VsZCBiZSBhbiBpbnRlcmVzdGluZyBub3ZlbCBnZW5lIHRvIGludmVzdGlnYXRlIHdpdGggcmVnYXJkIHRvIER1Y3RhbCBDYXJjaW5vbWEgX0luIFNpdHVfLgoKYGBge3IsIHdhcm5pbmc9RkFMU0V9ClNwYXRpYWxGZWF0dXJlUGxvdChvYmplY3QgPSBicmVhc3RfY2FuY2VyLCBmZWF0dXJlcyA9ICJNR1AiLCBhbHBoYSA9IGMoMC4xLCAxKSwgbmNvbCA9IDMpCmBgYAoKIyBNdWx0aXBsZSBTZWN0aW9ucwoKZm9yIHdvcmtzaG9wCmBgYHtyIGV2YWw9RkFMU0V9CmJyZWFzdF9jYW5jZXJfMiA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSAiL21udC9saWJzL3NoYXJlZF9kYXRhL2h1bWFuX2JyZWFzdF9jYW5jZXJfMi9vdXRzLyIsCiAgICAgICAgICAgICAgICBmaWxlbmFtZSA9ICJWMV9CcmVhc3RfQ2FuY2VyX0Jsb2NrX0FfU2VjdGlvbl8yX2ZpbHRlcmVkX2ZlYXR1cmVfYmNfbWF0cml4Lmg1IikKYGBgCmZvciAxMHgKYGBge3J9CmJyZWFzdF9jYW5jZXJfMiA8LSBMb2FkMTBYX1NwYXRpYWwoZGF0YS5kaXIgPSAiL21udC9hbmFseXNpcy9tYXJzb2MvcGlwZXN0YW5jZXMvSFdIVEZEU1hYL1NQQVRJQUxfUk5BX0NPVU5URVJfUEQvMTYzMDg3L0hFQUQvb3V0cy8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbGljZSA9ICJzbGljZTIiKQpgYGAKCmBgYHtyfQpicmVhc3RfY2FuY2VyX21lcmdlZCA8LSBtZXJnZShicmVhc3RfY2FuY2VyLCBicmVhc3RfY2FuY2VyXzIpCmBgYAoKQ291bnRzID0gVU1JCkZlYXR1cmVzID0gR2VuZXMKYGBge3IsIGZpZy53aWR0aD0xMCxmaWcuaGVpZ2h0PTEwLCB3YXJuaW5nPUZBTFNFfQpwbG90MSA8LSBTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlcl9tZXJnZWQsIGZlYXR1cmVzID0gIm5Db3VudF9TcGF0aWFsIikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQoKcGxvdDIgPC0gU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXJfbWVyZ2VkLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9TcGF0aWFsIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpCgpwbG90MSArIHBsb3QyICsgcGxvdF9sYXlvdXQobnJvdyA9IDIpCmBgYAoKIyMgTm9ybWFsaXplIG1lcmdlZCBkYXRhCgpUaGlzIHdpbGwgdGFrZSB+M21pbgoKRGVmYXVsdCBhc3NheSB3aWxsIG5vdyBiZSBzZXQgdG8gU0NUCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpicmVhc3RfY2FuY2VyX21lcmdlZCA8LSBTQ1RyYW5zZm9ybShicmVhc3RfY2FuY2VyX21lcmdlZCwgYXNzYXkgPSAiU3BhdGlhbCIsIHZlcmJvc2UgPSBUUlVFKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyX21lcmdlZCwgZmVhdHVyZXMgPSBjKCJFUkJCMiIsICJDRDhBIikpCmBgYAoKIyBTaW5nbGUgY2VsbC9udWNsZWkgaW50ZWdyYXRpb24KCkhlcmUgd2UgaGF2ZSBhIHByZXByb2Nlc3NlZCBTZXVyYXQgb2JqZWN0IHdpdGggMTBrIG51Y2xlaSBhbm5vdGF0ZWQgZnJvbSBhIGJyZWFzdCBjYW5jZXIgc2FtcGxlLiBEb24ndCBib3RoZXIgdG9vIG11Y2ggd2l0aCB0aGUgZGV0YWlscyBvZiBob3cgdGhpcyBkYXRhIHdhcyBnZW5lcmF0ZWQgdGhleSBkb24ndCBwYXJ0aWN1bGFybHkgbWF0dGVyIGZvciBvdXIgcHVycG9zZXMuIAoKIyMgTG9hZCB0aGUgU2V1cmF0IG9iamVjdAoKMTB4IGluZnJhc3RydWN0dXJlCmBgYHtyfQpiY19zblJOQSA8LSByZWFkUkRTKCIvbW50L2hvbWUvc3RlcGhlbi53aWxsaWFtcy95YXJkL09kaW4vU0lCXzIwMjBfV29ya3Nob3AvYmNfc25STkEucmRzIikKYGBgCgpGb3IgdGhlIHdvcmtzaG9wCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRX0KYmNfc25STkEgPC0gcmVhZFJEUygiL21udC9saWJzL3NoYXJlZF9kYXRhL2JjX3NuUk5BLnJkcyIpCmBgYAoKCmBgYHtyfQpiY19zblJOQQpgYGAKCkl0J3MgYWx3YXlzIGEgZ29vZCBpZGVhIHRvIHJlcnVuIG5vcm1hbGl6YXRpb24gdG8gbWFrZSBzdXJlIHlvdXIgZGF0YSBpcyBpbiB0aGUgY29ycmVjdCBmb3JtYXQgYmVmb3JlIG1vdmluZyBmb3J3YXJkIHdpdGggaW50ZWdyYXRpb24uCgpgYGAKYmNfc25STkEgPC0gU0NUcmFuc2Zvcm0oYmNfc25STkEsIG5jZWxscyA9IDMwMDAsIHZlcmJvc2UgPSBGQUxTRSkgJT4lIAogIFJ1blBDQSh2ZXJib3NlID0gRkFMU0UpICU+JSAKICBSdW5VTUFQKGRpbXMgPSAxOjMwKQpgYGAKCkNsYXNzCmBgYHtyLCBmaWcud2lkdGg9MTB9CkRpbVBsb3QoYmNfc25STkEsIGdyb3VwLmJ5ID0gImlkZW50IiwgbGFiZWwgPSBGQUxTRSkKYGBgClN1YmNsYXNzCmBgYHtyLCBmaWcud2lkdGg9MTB9CkRpbVBsb3QoYmNfc25STkEsIGdyb3VwLmJ5ID0gInN1YmNsYXNzIiwgbGFiZWwgPSBGQUxTRSkKYGBgCiMjIHNuUk5BIERpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcwoKV2hhdCBnZW5lcyBkZWZpbmUgc29tZSBjZWxsIHR5cGVzPwpgYGAKIyBGaW5kIG1hcmtlcnMgZm9yIGV2ZXJ5IGNsdXN0ZXIgY29tcGFyZWQgdG8gYWxsIHJlbWFpbmluZyBjZWxscywgcmVwb3J0IG9ubHkgdGhlIHBvc2l0aXZlIG9uZXMKIyBUaGlzIHRha2VzIGEgYml0IG9mIHRpbWUgc28gd2UnbGwgc2tpcCBpdCBhbmQgbW92ZSBvbiB0byBzcGVjaWZpYyBjZWxsIHR5cGVzCmRlX21hcmtlcnNfc25STkEgPC0gRmluZEFsbE1hcmtlcnMoYmNfc25STkEsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUpCmRlX21hcmtlcnNfc25STkEgJT4lIAogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSAKICB0b3BfbihuID0gMiwgd3QgPSBhdmdfbG9nRkMpCmBgYAoKRmluZCBtYXJrZXJzIHRoYXQgZGVmaW5lIHR1bW9ycwoKYGBge3J9CmRlX21hcmtlcnNfdHVtb3IgPC0gRmluZE1hcmtlcnMoYmNfc25STkEsIGlkZW50LjEgPSAiTGlrZWx5IHR1bW9yIGNlbGxzIiwgbG9nZmMudGhyZXNob2xkID0gMC4yNSwgdGVzdC51c2UgPSAicm9jIiwgb25seS5wb3MgPSBUUlVFKQpkZV9tYXJrZXJzX3R1bW9yICU+JQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgJT4lIAogIGFycmFuZ2UoLXBvd2VyKQpgYGAKCkZpbmQgbWFya2VycyB0aGF0IGRlZmluZSB0dW1vcnMKCmBgYHtyfQpkZV9tYXJrZXJzX3RjZWxsIDwtIEZpbmRNYXJrZXJzKGJjX3NuUk5BLCBpZGVudC4xID0gIlQgY2VsbHMiLCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1LCB0ZXN0LnVzZSA9ICJyb2MiLCBvbmx5LnBvcyA9IFRSVUUpCmRlX21hcmtlcnNfdGNlbGwgJT4lCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oImdlbmUiKSAlPiUgCiAgYXJyYW5nZSgtcG93ZXIpCmBgYAoKRmluZCBtYXJrZXJzIHRoYXQgZGVmaW5lIHN0ZW0gY2VsbHMKCmBgYHtyfQpkZV9tYXJrZXJzX3N0ZW1jZWxsIDwtIEZpbmRNYXJrZXJzKGJjX3NuUk5BLCBpZGVudC4xID0gIkNENDlmLWhpIE1hU0NzIiwgbG9nZmMudGhyZXNob2xkID0gMC4yNSwgdGVzdC51c2UgPSAicm9jIiwgb25seS5wb3MgPSBUUlVFKQpkZV9tYXJrZXJzX3N0ZW1jZWxsICU+JQogIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCJnZW5lIikgJT4lIAogIGFycmFuZ2UoLXBvd2VyKQpgYGAKCgojIyBJZGVudGlmeSBhbmQgVHJhbnNmZXIgQW5jaG9ycwoKYGBge3J9CmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBiY19zblJOQSwgcXVlcnkgPSBicmVhc3RfY2FuY2VyLG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIlNDVCIpCgpwcmVkaWN0aW9ucy5hc3NheSA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IGJjX3NuUk5BJHN1YmNsYXNzLCBwcmVkaWN0aW9uLmFzc2F5ID0gVFJVRSwgCiAgICB3ZWlnaHQucmVkdWN0aW9uID0gYnJlYXN0X2NhbmNlcltbInBjYSJdXSkKCmJyZWFzdF9jYW5jZXJbWyJwcmVkaWN0aW9ucyJdXSA8LSBwcmVkaWN0aW9ucy5hc3NheQoKRGVmYXVsdEFzc2F5KGJyZWFzdF9jYW5jZXIpIDwtICJwcmVkaWN0aW9ucyIKYGBgCgpMZXQncyBoYXZlIGEgbG9vayBhdCBvdXIgYW5ub3RhdGlvbnMgYWdhaW4uCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KY2EgPC0gcmVhZGJpdG1hcDo6cmVhZC5iaXRtYXAoImltYWdlcy9CcmVhc3QgQ2FuY2VyIFBhdGgucG5nIikKIyBpbiB0aGUgdHV0b3JpYWwKIyBjYSA8LSByZWFkYml0bWFwOjpyZWFkLmJpdG1hcCgnL21udC9saWJzL3NoYXJlZF9kYXRhL2h1bWFuX2JyZWFzdF9jYW5jZXJfMS9pbWFnZXMvQnJlYXN0X0NhbmNlcl9QYXRoLnBuZycpCnBsb3QoMDoxLDA6MSx0eXBlPSJuIixhbm49RkFMU0UsYXhlcz1GQUxTRSkKcmFzdGVySW1hZ2UoY2EsMCwwLDEsMSkKYGBgCgoKIyMgSW1tdW5lIE1pY3JvZW52aXJvbm1lbnQKIyMjIFQgY2VsbCBzdWJ0eXBlcwoKV2hhdCBhYm91dCB0aGUgaW1tdW5lIG1pY3JvZW52aXJvbm1lbnQ/IAoKRHVjYWwgQ2FyY2lub21hIF9pbiBzaXR1XyBpcyBkZXBsZXRlZCBvZiBULWNlbGxzCmBgYHtyLCBmaWcud2lkdGg9MTUsIHdhcm5pbmc9RkFMU0V9CihTcGF0aWFsRmVhdHVyZVBsb3QoYnJlYXN0X2NhbmNlciwgCiAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGMoIlQgY2VsbHMtMCIpLCAKICAgICAgICAgICAgICAgICAgIHB0LnNpemUuZmFjdG9yID0gMS41LCBuY29sID0gMiwgY3JvcCA9IFRSVUUpIHwKU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIAogICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUIGNlbGxzLTEiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSwgbmNvbCA9IDIsIGNyb3AgPSBUUlVFKSkgLwooU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIAogICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUIGNlbGxzLTIiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSwgbmNvbCA9IDIsIGNyb3AgPSBUUlVFKSB8ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVCBjZWxscy01IiksIAogICAgICAgICAgICAgICAgICAgcHQuc2l6ZS5mYWN0b3IgPSAxLjUsIG5jb2wgPSAyLCBjcm9wID0gVFJVRSkpCmBgYAoKIyMjIEIgY2VsbCBzdWJ0eXBlcwoKQiBjZWxscyBhcmUgZW5yaWNoZWQgaW4gdGhlIGZpYnJvdXMgdGlzc3VlIG91dHNpZGUgdGhlIHR1bW9yCmBgYHtyLCBmaWcud2lkdGg9MTUsIHdhcm5pbmc9RkFMU0V9ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiQiBjZWxscyIpLCAKICAgICAgICAgICAgICAgICAgIHB0LnNpemUuZmFjdG9yID0gMS41LCBuY29sID0gMiwgY3JvcCA9IFRSVUUpCmBgYAoKVGhlcmUgc2VlbSB0byBiZSBzb21lIGR1Y3RhbCBjZWxscyBidXQgaGF2ZSBhIGxvb2sgYXQgb3VyIHNjb3JlLiBBcmUgd2UgY29uZmlkZW50IGluIHRoaXMgYXNzZXJ0aW9uPyAKYGBge3IsIGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0KU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIAogICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJEdWN0YWwgY2VsbHMiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSwgIGNyb3AgPSBUUlVFKQpgYGAKIyMgVHVtb3IgU3VidHlwZXMKCkl0IGxvb2tzIGxpa2UgdGhlIGR1Y2FsIGNhcmNpbm9tYSBfaW4gc2l0dV8gaXMgZW5yaWNoZWQgZm9yIHR1bW9yIHN1YnR5cGVzIDgsIDEwLCBhbmQgMTIgYnV0IG5vdCAzLiAKYGBge3IsIGZpZy53aWR0aD0xNSwgd2FybmluZz1GQUxTRX0KKFNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVHVtb3IgY2VsbHMtMyIpLCAKICAgICAgICAgICAgICAgICAgIHB0LnNpemUuZmFjdG9yID0gMS41LCBuY29sID0gMiwgY3JvcCA9IFRSVUUpIHwKU3BhdGlhbEZlYXR1cmVQbG90KGJyZWFzdF9jYW5jZXIsIAogICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSBjKCJUdW1vciBjZWxscy04IiksIAogICAgICAgICAgICAgICAgICAgcHQuc2l6ZS5mYWN0b3IgPSAxLjUsIG5jb2wgPSAyLCBjcm9wID0gVFJVRSkpIC8KKFNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVHVtb3IgY2VsbHMtMTAiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSwgbmNvbCA9IDIsIGNyb3AgPSBUUlVFKSB8ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiVHVtb3IgY2VsbHMtMTIiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSwgbmNvbCA9IDIsIGNyb3AgPSBUUlVFKSkKYGBgCgpMaWtlIHRoZSBEdWN0YWwgQ2VsbHMsIHdlIG1pZ2h0IG5vdCBiZSBhcyBjb25maWRlbnQgaW4gdGhlIFR1bW9yIFN0ZW0gQ2VsbHMgYnV0IHRoaXMgbWlnaHQgbWFrZSBzZW5zZSBjb25zaWRlcmluZyB0aGUgMTB4IHNuUk5BIGRhdGFzZXQgYW5kIHRoZSBWaXNpdW0gZGF0YXNldCBhcmUgZnJvbSBkaWZmZXJlbnQgaW5kaXZpZHVhbHMuCmBgYHtyLCBmaWcud2lkdGg9MTAsIHdhcm5pbmc9RkFMU0V9ClNwYXRpYWxGZWF0dXJlUGxvdChicmVhc3RfY2FuY2VyLCAKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gYygiQ0Q0OWYtaGkgTWFTQ3MiKSwgCiAgICAgICAgICAgICAgICAgICBwdC5zaXplLmZhY3RvciA9IDEuNSxjcm9wID0gVFJVRSkgKyAKcGxvdF9hbm5vdGF0aW9uKAogIHRpdGxlID0gJ1R1bW9yIFN0ZW0gQ2VsbHMnKQpgYGAK